UnitTest = {}

function assert_fails(func, ...)
	local done,err = pcall(func)
	for i=1,select("#", ...) do
		local msg = select(i, ...)
		assert(not done and string.find(err, msg), "\n|cffffff00Did not find fails match: |r\n" .. msg .. "\n|cffffff00In error:|r \n" .. tostring(err) .. "\n|cffffff00Stack traceback:|r\n".. tostring(debugstack()))
	end
	assert(not done, "Function did not fail")
end

function argerror(arg)
	return string.format("bad argument #%d", arg)
end

local function xerr(msg)
	return msg .. "\n" .. debugstack()	
end

local function cleanError(err)
	err = err:gsub(".*(|c%x+Did not find fails match:)","%1")
	err = err:gsub("[^\n]*\\([^\\]+%.lua:%d+:)","%1")
	return err
end

local frame = CreateFrame("ScrollingMessageFrame", "UnitTestFrame", UIParent)
frame:SetHeight(400)
frame:SetWidth(600)
frame:SetPoint("CENTER", 0, 0)
local backdrop = 
{
	bgFile = "Interface/Tooltips/UI-Tooltip-Background",
	tile = false,
	tileSize = 6,
	edgeSize = 18,
	insets = {
		left = -4,
		right = -4,
		top = -4,
		bottom = -4
	}
}
frame:SetBackdrop(backdrop)
frame:SetBackdropColor(0.3, 0.3, 0.3)

frame:SetFont("Interface\\AddOns\\DongleUnitTests\\MONACO.TTF", 14)
frame:SetJustifyH("LEFT")
frame:SetFadeDuration(10)
frame:SetTimeVisible(180)
frame:SetMaxLines(9999)
frame:SetScript("OnMouseWheel", function (self, delta)
	if delta > 0 then self:ScrollUp()
	elseif delta < 0 then
		if IsShiftKeyDown() then self:ScrollToBottom()
		else self:ScrollDown() end
	end
end)
frame:EnableMouseWheel(1)
local fails = {}
frame:SetScript("OnHyperlinkClick",function(self, link, text, button)
	
	ItemRefTooltip:ClearLines()
	ItemRefTooltip:SetOwner(UIParent,"ANCHOR_PRESERVE")
	
	local failID, testName = link:match("fail:(%d+):([%a_]+)")
	failID = tonumber(failID)
	local errString = cleanError(fails[failID])
	
	ItemRefTooltip:AddLine(testName,1,.2,.2)
	
	for line in errString:gmatch("([^\n]*)") do
		ItemRefTooltip:AddLine(line,1,1,1)
	end    
	
	ItemRefTooltip:Show()
end)


local print = function(msg)
	UnitTestFrame:AddMessage(msg)
end

local __unitTests = {}

function UnitTest:New(it, name)
	if type(it) == "string" then
		name = it
		it = nil
	end
	
	it = it or {}
	setmetatable(it, self)
	self.__index = self
	__unitTests[name] = true
	return it
end

function UnitTest:Run(...)
	local function run_test(t, name)
		local genv = getfenv(0)
		local penv = setmetatable({["__unitTests"] = __unitTests}, {__index=genv})
		setfenv(t, penv)
		setfenv(0, penv)
		local status, err = xpcall(t, xerr)
		setfenv(0, genv)

		if status then
			print(("%-39s |cFF11FF11pass|r"):format("[" .. name .. "]"))
		else
			local failID = #fails + 1
			fails[failID] = err
			print(("%-38s |cFFFF1111|Hfail:%d:%s|h[FAIL]|h|r"):format("[" .. name .. "]", failID, name))
		end
		
		for k,v in pairs(penv) do
			--print(string.format("%-39s |cFFFFFF11Global leak: %s|r", "", k))
		end
	end
  
	for k, v in pairs(self) do
		run_test(v, k)
	end
end
